package com.weblog.user.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.weblog.model.article.output.ArticleCusVo;
import com.weblog.model.user.CusCategory;
import com.weblog.model.user.CusCategoryInfo;
import com.weblog.user.client.ArticleClient;
import com.weblog.user.dao.CusCategoryDao;
import com.weblog.user.enums.ResultEnum;
import entity.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import util.IdWorker;
import util.MapSizeUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author MaoLin Wang
 * @date 2019/11/122:12
 */
@Service
public class CusCategoryService {

    @Autowired
    private CusCategoryDao cusCategoryDao;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RedisTemplate jsonRedisTemplate;

    @Autowired
    private ArticleClient articleClient;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private MapSizeUtil mapSizeUtil;

    private static final String KEY_ID = "id";
    private static final String KEY_NAME = "name";
    private static final String KEY_DISPLAY = "display";
    private static final String KEY_ARTICLe_COUNT = "article_count";
    private static final String KEY_AIDS = "aids";
    private static final String KEY_STATE = "state";

    private static final String REDIS_KEY = "weblog_user_cuscategories_";
    private static final String TARGET_DISPLAY_VALUE = "2";


    /**
     * 条件查询
     * TODO 改成vo
     * @param searchMap
     * @return 符合条件的自定义分类集合
     */
    public List<CusCategoryInfo> multiSearch(Map<String, String> searchMap) {

        String userid = searchMap.get("userid");

        if (userid == null || "".equals(userid)) {
            userid = (String) request.getAttribute("id");
        }

        //查询值
        String targetDisplay = searchMap.get(KEY_DISPLAY);
        String targetName = searchMap.get(KEY_NAME);

        //根据展示状态查询

        if (!"".equals(targetDisplay) && targetDisplay != null) {
            if (TARGET_DISPLAY_VALUE.equals(targetDisplay)) {
                //2表示不限制状态
                return categoriesAll();
            }
            return handleQuery(userid, targetDisplay, KEY_DISPLAY, 1);
        } else if (!"".equals(targetName) && targetName != null) {
            //根据分类名查询
            return handleQuery(userid, targetName, KEY_NAME, 0);
        } else {
            //没有查询条件
            return categoriesAll();
        }

    }

    /**
     * 处理根据条件查询
     *
     * @param userid     当前用户id
     * @param targetName 待查询条件  展示状态或分类名
     * @param keyName    KEY值
     * @return
     */
    private List<CusCategoryInfo> handleQuery(String userid, String targetName, String keyName, int type) {
        List<CusCategoryInfo> resultList;

        List<CusCategoryInfo> cusCategoryInfos = parseJson(userid);
        resultList = new ArrayList<>();

        for (CusCategoryInfo category : cusCategoryInfos) {
            if (type == 1) {
                if (targetName.equals(category.getDisplay()) && "1".equals(category.getState())) {

                }
            } else {
                if (targetName.equals(category.getName()) && "1".equals(category.getState())) {
                    CusCategoryInfo info = null;
                    handleResult(resultList, category, info);
                }
            }

        }
        return resultList;
    }

    /**
     * 查询所有自定义分类信息
     *
     * @return 所有自定义分类信息集合
     */
    public List<CusCategoryInfo> categoriesAll() {
        String userid = (String) request.getAttribute("id");
        //查询缓存
        List<CusCategoryInfo> redisData = (List<CusCategoryInfo>) jsonRedisTemplate.opsForValue().get(REDIS_KEY + userid);
        if (redisData != null) {
            return redisData;
        } else {
            //结果集
            List<CusCategoryInfo> resultList = new ArrayList<>();

            List<CusCategoryInfo> cusCategoryInfos = parseJson(userid);
            CusCategoryInfo map = null;
            for (CusCategoryInfo category : cusCategoryInfos) {
                if ("1".equals(category.getState())) {
                    //只查询未在回收站的分类
                    handleResult(resultList, category, map);
                }
            }
            //添加缓存
            jsonRedisTemplate.opsForValue().set(REDIS_KEY + userid, resultList);
            return resultList;
        }
    }

    /**
     * 添加分类
     *
     * @param addMap
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum add(Map<String, String> addMap) {
        String userid = (String) request.getAttribute("id");
        //操作用户id和当前用户id匹配
        if (userid.equals(addMap.get("userid"))) {
            List<CusCategoryInfo> raw_list = parseJson(userid);
            boolean exist = checkCusCategory(raw_list, addMap.get(KEY_NAME));
            if (false == exist) {
                CusCategoryInfo new_Cus = new CusCategoryInfo();
                new_Cus.setId(idWorker.nextId() + "");
                new_Cus.setName(addMap.get(KEY_NAME));
                new_Cus.setDisplay(addMap.get(KEY_DISPLAY));
                new_Cus.setState("1");
                List<String> aids = new ArrayList<>();
                new_Cus.setAids(aids);
                raw_list.add(new_Cus);
                /*
                    WriteMapNullValue:是否输出值为null的字段,默认为false
                    WriteNullListAsEmpty:List字段如果为null,输出为[],而非null
                 */
                String jsonStr = JSON.toJSONString(raw_list, SerializerFeature.WriteMapNullValue,
                        SerializerFeature.WriteNullListAsEmpty);
                CusCategory newCuc = new CusCategory();
                newCuc.setUserid(userid);
                newCuc.setCategories(jsonStr);
                cusCategoryDao.save(newCuc);
                jsonRedisTemplate.delete(REDIS_KEY + userid);
                return ResultEnum.OK;
            }
            return ResultEnum.TARGET_EXISTEED;

        }
        return ResultEnum.ACCESS_ERROR;


    }

    /**
     * 校验新添加的自定义分类
     *
     * @param name 分类名
     */
    private boolean checkCusCategory(List<CusCategoryInfo> raw_list, String name) {
        for (CusCategoryInfo category : raw_list) {
            if (name.equalsIgnoreCase(category.getName())) {
                //已存在
                return true;
            }
        }
        return false;

    }

    /**
     * 彻底删除分类
     *
     * @param id 分类id
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum delete(String id) {
        String userid = (String) request.getAttribute("id");

        if (!"".equals(userid) || userid != null) {
            List<CusCategoryInfo> cusCategoryInfos = parseJson(userid);
            for (CusCategoryInfo category : cusCategoryInfos) {
                if (id.equals(category.getId())) {
                    cusCategoryInfos.remove(category);
                    String jsonStr = JSON.toJSONString(cusCategoryInfos, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
                    cusCategoryDao.updateContent(userid, jsonStr);
                    //1ms过期
                    jsonRedisTemplate.delete(REDIS_KEY + userid);
                    break;
                }
            }
            return ResultEnum.OK;
        } else {
            return ResultEnum.ACCESS_ERROR;
        }

    }

    /**
     * 删除分类到回收站
     *
     * @param id 分类id
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum recycle(String id) {
        String userid = (String) request.getAttribute("id");

        if (!"".equals(userid) && userid != null) {
            List<CusCategoryInfo> categoriesList = parseJson(userid);
            for (CusCategoryInfo category : categoriesList) {
                if (id.equals(category.getId())) {
                    category.setState("0");
                    String jsonStr = JSON.toJSONString(categoriesList, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
                    cusCategoryDao.updateContent(userid, jsonStr);
                    //1ms过期
                    jsonRedisTemplate.delete(REDIS_KEY + userid);
                    break;
                }
            }
            return ResultEnum.OK;
        } else {
            return ResultEnum.ACCESS_ERROR;
        }
    }

    /**
     * 解析json
     *
     * @param userid 用户id
     */
    private List<CusCategoryInfo> parseJson(String userid) {
        CusCategory cusCategory = cusCategoryDao.findById(userid).get();
        String categoriesJson = cusCategory.getCategories();
        return JSON.parseArray(categoriesJson, CusCategoryInfo.class);

    }

    /**
     * 封装结果集
     *
     * @param resultList 结果集
     * @param category   每个分类对象
     */
    private void handleResult(List<CusCategoryInfo> resultList, CusCategoryInfo category, CusCategoryInfo curInfo) {
        curInfo = new CusCategoryInfo();
        curInfo.setId(category.getId());
        curInfo.setName(category.getName());
        curInfo.setDisplay(category.getDisplay());
        curInfo.setState(category.getState());
        curInfo.setArticle_count(category.getAids().size());
        resultList.add(curInfo);
    }

    /**
     * 修改自定义分类名
     *
     * @param updateMap 修改实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum updateName(Map<String, String> updateMap) {
        String userid = (String) request.getAttribute("id");

        if (!"".equals(userid) || userid != null) {
            List<CusCategoryInfo> categoriesList = parseJson(userid);
            boolean exist = checkCusCategory(categoriesList, updateMap.get(KEY_NAME));
            if (false == exist) {
                //目标分类名不存在
                for (CusCategoryInfo category : categoriesList) {
                    if (category.getId().equals(updateMap.get(KEY_ID))) {
                        category.setName(updateMap.get(KEY_NAME));
                        String jsonStr = JSON.toJSONString(categoriesList, SerializerFeature.WriteMapNullValue,
                                SerializerFeature.WriteNullListAsEmpty);
                        cusCategoryDao.updateContent(userid, jsonStr);
                        //1ms过期
                        jsonRedisTemplate.delete(REDIS_KEY + userid);
                        return ResultEnum.OK;

                    }

                }
                //待修改分类已被删除
                return ResultEnum.TARGET_NOT_FOUND;
            }
            //目标分类已存在
            return ResultEnum.TARGET_EXISTEED;

        } else {
            return ResultEnum.ACCESS_ERROR;
        }
    }

    /**
     * 修改前台展示状态
     *
     * @param updateMap 修改对象
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum updateDisplay(Map<String, String> updateMap) {
        String userid = (String) request.getAttribute("id");

        if (!"".equals(userid) || userid != null) {
            List<CusCategoryInfo> categoriesList = parseJson(userid);
            for (CusCategoryInfo category : categoriesList) {
                if (category.getId().equals(updateMap.get(KEY_ID))) {
                    category.setDisplay(updateMap.get(KEY_DISPLAY));
                    String jsonStr = JSON.toJSONString(categoriesList, SerializerFeature.WriteMapNullValue,
                            SerializerFeature.WriteNullListAsEmpty);
                    cusCategoryDao.updateContent(userid, jsonStr);
                    //1ms过期
                    jsonRedisTemplate.delete(REDIS_KEY + userid);
                    return ResultEnum.OK;
                }
            }
            //待修改分类已被删除
            return ResultEnum.TARGET_NOT_FOUND;

        } else {
            return ResultEnum.ACCESS_ERROR;
        }
    }

    /**
     * 根据分类id查询该分类的文章信息
     *
     * @param userId
     * @param id
     */
    public List<ArticleCusVo> queryCucArticle(String userId, String id) {
        if ("".equals(userId) || userId == null) {
            userId = (String) request.getAttribute("id");
        }
        List<String> aids = queryAids(userId, id);

        if (aids != null && aids.size() > 0) {
            Result result = articleClient.cucArticle(aids);
            if (result.getData() != null) {
                List<ArticleCusVo> list = (List<ArticleCusVo>) result.getData();
                return list;
            }
            return null;
        }
        return null;

    }

    /**
     * 批量删除分类文章
     *
     * @param batchData
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchRemoveArticle(Map<String, Object> batchData) {
        handleBatch(batchData, 1);
    }

    /**
     * 批量复制文章到另一个分类中
     *
     * @param copyData {id:targetid} , {aids:[aid1,aid2..]}
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum batchCopyArticle(Map<String, Object> copyData, String currentid) {
        if (currentid.equals(copyData.get(KEY_ID))) {
            return ResultEnum.TARGET_SELF;
        }
        boolean flag = handleBatch(copyData, 2);
        if (flag == false) {
            return ResultEnum.TARGET_EXISTEED;
        }
        return ResultEnum.OK;
    }

    /**
     * 批量移动
     *
     * @param moveData
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum batchMove(Map<String, Object> moveData) {
        if (moveData.get(KEY_ID).equals(moveData.get("targetId"))) {
            return ResultEnum.TARGET_SELF;
        }
        boolean flag = handleBatchMove(moveData, 3);
        if (flag == false) {
            return ResultEnum.TARGET_EXISTEED;
        }
        return ResultEnum.OK;
    }

    /**
     * 处理批量移动
     *
     * @param moveData
     * @param type
     * @return
     */
    private boolean handleBatchMove(Map<String, Object> moveData, int type) {
        String cucId = (String) moveData.get(KEY_ID);
        String targetId = (String) moveData.get("targetId");
        List<String> aids = (List<String>) moveData.get(KEY_AIDS);
        String userid = (String) request.getAttribute("id");
        List<CusCategoryInfo> categories = parseJson(userid);
        List<String> rawAids = null;
        //目标分类中已存在待移动文章
        boolean flag = false;
        //完成移动操作
        boolean finishDelete = false;
        boolean finishAdd = false;
        for (CusCategoryInfo category : categories) {
            if (category.getId().equals(cucId) && !finishDelete) {
                rawAids = (List<String>) category.getAids();
                //批量移动
                // 删除当前分类的要移动的文章
                rawAids.removeAll(aids);
                category.setAids(rawAids);
                finishDelete = true;

            }
            if (category.getId().equals(targetId) && !finishAdd) {
                //批量移动到目标分类
                rawAids = (List<String>) category.getAids();
                aids.removeAll(rawAids);
                if (aids.size() > 0) {
                    rawAids.addAll(aids);
                    flag = true;
                    finishAdd = true;
                    category.setAids(rawAids);
                }

            }
            if (finishAdd && finishDelete) {
                //完成目标分类的添加和当前分类的删除
                break;
            }

        }
        if (flag == true) {
            String json = JSON.toJSONString(categories, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
            cusCategoryDao.updateContent(userid, json);
            jsonRedisTemplate.delete(REDIS_KEY + userid);
        }
        return flag;
    }

    /**
     * 批量添加
     *
     * @param addData
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultEnum batchAdd(Map<String, Object> addData) {
        boolean result = handleBatch(addData, 3);
        if (result) {
            return ResultEnum.OK;
        }
        return ResultEnum.EROOR;

    }

    /**
     * 处理批量操作
     *
     * @param batchData 批量数据
     * @param type      操作类型 ，1删除，2复制 3 添加
     */
    private boolean handleBatch(Map<String, Object> batchData, int type) {
        if (type != 1 && type != 2 && type != 3) {
            return false;
        }
        String operId = (String) batchData.get(KEY_ID);
        List<String> aids = (List<String>) batchData.get(KEY_AIDS);
        String userid = (String) request.getAttribute("id");
        List<CusCategoryInfo> categories = parseJson(userid);
        //目标分类中已存在待复制文章
        boolean flag = false;
        //完成移动操作
        for (CusCategoryInfo category : categories) {

            if (category.getId().equals(operId)) {
                List<String> rawAids = category.getAids();
                switch (type) {
                    case 1:
                        //批量删除
                        rawAids.removeAll(aids);
                        flag = true;
                        break;
                    case 2:
                        //批量复制
                        //先出掉重复的
                        aids.removeAll(rawAids);
                        if (aids.size() > 0) {
                            rawAids.addAll(aids);
                            flag = true;
                        }
                        break;
                    case 3:
                        //批量添加
                        flag = true;
                        rawAids.addAll(aids);
                        break;
                    default:
                        flag = true;
                        break;
                }

                category.setAids(rawAids);
                break;
            }
        }
        if (flag == true) {
            String json = JSON.toJSONString(categories, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
            cusCategoryDao.updateContent(userid, json);
            jsonRedisTemplate.delete(REDIS_KEY + userid);
        }
        return flag;
    }


    /**
     * 文章客户端调用，查询分类的aids，不封装文章信息
     *
     * @param userId 用户id
     * @param id     分类id
     * @return
     */
    public List<String> queryAids(String userId, String id) {

        List<CusCategoryInfo> cusCategoryInfos = parseJson(userId);
        List<String> aids = null;
        for (CusCategoryInfo category : cusCategoryInfos) {
            if (category.getId().equals(id)) {
                aids = category.getAids();
                break;
            }
        }
        return aids;
    }


    /**
     * 删除分类中的单个文章
     *
     * @param cucId 分类id
     * @param aid   文章id
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeSingleArticle(String cucId, String aid) {
        String userid = (String) request.getAttribute("id");
        List<CusCategoryInfo> cusCategoryInfos = parseJson(userid);
        for (CusCategoryInfo cusCategoryInfo : cusCategoryInfos) {
            if (cusCategoryInfo.getId().equals(cucId)) {
                List<String> aids = cusCategoryInfo.getAids();
                aids.remove(aid);
                cusCategoryInfo.setAids(aids);
                break;
            }
        }
        String json = JSON.toJSONString(cusCategoryInfos, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
        cusCategoryDao.updateContent(userid, json);
        jsonRedisTemplate.delete(REDIS_KEY + userid);
    }
}
